package c2.cross.business.boss;

import c2.cross.business.CrossBody;
import c2.cross.business.base.CrossModule;
import c2.cross.business.boss.data.CrossBossKV;
import c2.cross.business.boss.data.CrossBossSingleData;
import cate.common.game.mail.MailCmd;
import cate.common.table.cross_boss.base.CrossBossFarmBaseRow;
import cate.common.table.d.GD;
import cate.common.table.d.GDOperation;
import cate.common.table.res.drop.row.DropRow;
import cate.game.admin.cross.CrossAdminCMDs;
import cate.game.admin.cross.CrossAdminReq;
import cate.game.db.mongo.kv.KvMongo;
import cate.game.farm.local.cross_boss.CrossBossConstants;
import cate.game.farm.local.cross_boss.data.*;
import cate.game.res.MixRes;
import cate.game.res.drop.DropConfigHelper;
import cp.solution.rpc.RpcMsgHead;
import easy.java.dev.note.NoteClass;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Random;
import java.util.stream.Collectors;

@Slf4j
@NoteClass("跨服BOSS主模块")
public class CrossBossModule extends CrossModule<CrossBossKV> {
    public CrossBossModule(CrossBody context) {
        super(context);
    }

    @Override
    protected String getStatusKey() {
        return KvMongo.KEY_CROSS_BOSS_DATA;
    }

    @Override
    protected Class<CrossBossKV> getStatusClass() {
        return CrossBossKV.class;
    }

    @Override
    public String getName() {
        return "跨服BOSS";
    }

    @Override
    public void initDependent() throws Exception {
        super.initDependent();
        // 加载常量
        CrossBossConstants.loadFromTable(table().common);
        // 配置检测
        for (CrossBossFarmBaseRow row : table().crossBossFarm.base.getList()) {
            if (!status.bossMap.containsKey(row.id)) {
                CrossBossSingleData singleData = buildSingleData(row);
                status.bossMap.put(row.id, singleData);
            }
        }
        status.bossMap.entrySet().removeIf(e -> table().crossBossFarm.base.get(e.getKey()) == null);
        status.bossMap.values().forEach(CrossBossSingleData::init);
        // 注册回调
        rpc().recv().onRequestResponseTemplate(CrossBossInnerMsg.OVERALL_BOSS_INFO, Void.class, this::overallBossInfo);
        rpc().recv().onRequestResponseTemplate(CrossBossInnerMsg.VIEW_BOSS_DETAIL, CBIViewBossDetail.class, this::detailBossVO);
        rpc().recv().onRequestResponseTemplate(CrossBossInnerMsg.TRY_FIGHT_BOSS, Integer.class, this::tryFightBoss);
        rpc().recv().onFireAndForgetTemplate(CrossBossInnerMsg.REPORT_FIGHT_RESULT, CBIReportFightResult.class, this::reportFightResult);
        // 注册GM
        admin().functionRegister(CrossAdminCMDs.CROSS_BOSS_RESET_ALL, this::GMReset);
    }

    @Override
    protected int getIntervalSeconds() {
        return 1;
    }

    @Override
    protected void onInterval() throws Exception {
        super.onInterval();
        long nowTime = System.currentTimeMillis();
        boolean changed = false;
        for (CrossBossSingleData data : status.bossMap.values()) {
            boolean changeThis = data.tick(nowTime, getBaseRow(data.id));
            changed = changed || changeThis;
        }
        if (changed) {
            broadcastInfo();
        }
    }

    /**
     * 获取基础配置
     */
    private CrossBossFarmBaseRow getBaseRow(int id) {
        return table().crossBossFarm.base.get(id);
    }

    /**
     * 根据配置构建单体BOSS数据
     *
     * @param row 配置项
     * @return 单体BOSS数据
     */
    private CrossBossSingleData buildSingleData(CrossBossFarmBaseRow row) {
        CrossBossSingleData singleData = new CrossBossSingleData();
        singleData.id = row.id;
        singleData.curHp = row.maxHp;
        return singleData;
    }

    /**
     * 广播BOSS信息变更
     */
    private void broadcastInfo() {
        try {
            rpc().send().fireAndForgetGameInCrossTemplate(CrossBossInnerMsg.BROADCAST_OVERALL,
                    code(),
                    buildOverallVO());
        } catch (Exception e) {
            log.error("", e);
        }
    }

    /**
     * 获取跨服BOSS整体简要数据
     *
     * @param head 消息头
     * @param v    虚空请求数据
     * @return 简要数据汇总
     */
    private CrossBossOverallVO overallBossInfo(RpcMsgHead head, Void v) {
        return buildOverallVO();
    }

    /**
     * 构建整体简要数据
     */
    private CrossBossOverallVO buildOverallVO() {
        CrossBossOverallVO vo = new CrossBossOverallVO();
        vo.bossMap = status.bossMap.values().stream()
                .map(CrossBossSingleData::toSimple)
                .collect(Collectors.toMap(o -> o.id, o -> o));
        return vo;
    }

    /**
     * 查看BOSS详细信息
     *
     * @param head  消息头
     * @param param 请求参数
     * @return BOSS详细信息
     */
    private CrossBossDetailVO detailBossVO(RpcMsgHead head, CBIViewBossDetail param) {
        if (param == null) {
            return null;
        }
        if (!status.bossMap.containsKey(param.id)) {
            return null;
        }
        return status.bossMap.get(param.id).toDetail(param.uid);
    }

    /**
     * 尝试发起战斗
     *
     * @param head 消息头
     * @param id   BOSS配置ID
     * @return BOSS当前血量
     */
    private Long tryFightBoss(RpcMsgHead head, Integer id) {
        if (id == null || !status.bossMap.containsKey(id)) {
            return -1L;
        }
        return status.bossMap.get(id).getCurHpAndLock();
    }

    /**
     * 上报战斗结果
     *
     * @param head  消息头
     * @param param 参数
     * @return 是否击杀
     */
    private void reportFightResult(RpcMsgHead head, CBIReportFightResult param) {
        if (param == null || param.snapshot == null) {
            return;
        }
        if (!status.bossMap.containsKey(param.id)) {
            return;
        }
        CrossBossFarmBaseRow baseRow = getBaseRow(param.id);
        if (baseRow == null) {
            return;
        }
        CrossBossSingleData bossData = status.bossMap.get(param.id);
        boolean killed = bossData.updateRoleDamage(param.snapshot, param.damage, baseRow);
        if (killed) {
            MailCmd mailCmd = new MailCmd().addRole(param.snapshot.uid)
                    .withSrvId(param.snapshot.base.srvId)
                    .withOpr(GDOperation.CROSS_BOSS_FARM_KILL)
                    .withContent(CrossBossConstants.KILL_BOSS_REWARD_MAIL, new ArrayList<>())
                    .withReward(baseRow.killRewardStr);
            context.common.sendMail(mailCmd);
            broadcastInfo();
            bossData.rankList.forEach(rank -> {
                long damage = rank.value;
                int add = (int) (damage * baseRow.rewardExtraParam / baseRow.maxHp);
                MixRes reward = new MixRes();
                Random random = new Random();
                int rnd = random.nextInt(GD.W_10000);
                if (add + baseRow.dropBaseWeight >= rnd) {
                    DropRow dropRow = table().drop.config.get(baseRow.dropPackId);
                    if (dropRow != null) {
                        reward = DropConfigHelper.getDropReward(dropRow);
                    }
                }
                if (!reward.isEmpty()) {
                    MailCmd extraMail = new MailCmd().addRole(param.snapshot.uid)
                            .withSrvId(param.snapshot.base.srvId)
                            .withContent(CrossBossConstants.BOSS_EXTRA_REWARD_MAIL, new ArrayList<>())
                            .withOpr(GDOperation.CROSS_BOSS_FARM_EXTRA)
                            .withReward(reward.toItemsStr());
                    context.common.sendMail(extraMail);
                }
            });
        }
    }

    /**
     * GM重置跨服BOSS数据
     */
    private String GMReset(CrossAdminReq req) {
        status.bossMap.values().forEach(data -> {
            CrossBossFarmBaseRow baseRow = getBaseRow(data.id);
            data.reset(baseRow);
        });
        broadcastInfo();
        return "清除成功!";
    }
}
